package com.huanzhidadi.rollback.biz.impl;

import com.huanzhidadi.rollback.biz.UserBiz;
import com.huanzhidadi.rollback.exception.BaseException;
import com.huanzhidadi.rollback.model.Address;
import com.huanzhidadi.rollback.model.User;
import com.huanzhidadi.rollback.model.UserVO;
import com.huanzhidadi.rollback.service.AddressService;
import com.huanzhidadi.rollback.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Slf4j
@Service
public class UserBizImpl implements UserBiz {

    @Autowired
    private UserService userService;

    @Autowired
    private AddressService addressService;

    /**
     * 父方法加@Transactional注解，捕获异常，手动回滚事务
     * 子方法不加注解，不捕获异常，抛出异常
     * 另一个子方法回滚事务
     * @param userVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveUser1(UserVO userVO) {
        User user = new User();
        user.setName(userVO.getName());
        user.setAge(userVO.getAge());
        userService.save(user);

        Address address = new Address();
        address.setUserId(user.getId());
        address.setAddr(userVO.getAddr());
        addressService.insertException(address);
        return 1;
    }

    /**
     * 父方法加@Transactional(rollbackFor = Exception.class)注解，抛出异常
     * 子方法不加注解，不捕获异常，抛出异常
     * 另一个子方法回滚事务
     *
     * @Transactional(rollbackFor = Exception.class) 配合 throws Exception 自动回滚
     * @param userVO
     * @return
     * @throws BaseException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveUser2(UserVO userVO) throws BaseException {
        User user = new User();
        user.setName(userVO.getName());
        user.setAge(userVO.getAge());
        userService.insertWithoutTransactional(user);

        Address address = new Address();
        address.setUserId(user.getId());
        address.setAddr(userVO.getAddr());
        addressService.insertException(address);
        return 1;
    }

    /**
     * 父方法加@Transactional注解，父方法产生并捕获异常，手动回滚事务
     * 子方法不加注解
     * 所有子方法回滚事务
     * @Transactional 配合 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 手动回滚
     * 需配合@Transactional
     * 不用加rollbackFor
     * 子service不用加事务注解
     * @param userVO
     * @return
     */
    @Override
    @Transactional
    public int saveUser3(UserVO userVO) {
        try {
            User user = new User();
            user.setName(userVO.getName());
            user.setAge(userVO.getAge());
            userService.insertWithoutTransactional(user);

            Address address = new Address();
            address.setUserId(user.getId());
            address.setAddr(userVO.getAddr());
            addressService.insertWithoutTransactional(address);
            Integer age = 100 / userVO.getAge();
            return 1;
        } catch (Exception e) {
            //关键点，出异常后回滚方法内的数据库操作
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("数据库操作异常", e);
        }
        return -1;
    }

    /**
     * 父方法不加注解，产生异常并抛出，手动回滚
     * 子方法加@Transactional(rollbackFor = Exception.class)注解
     * 子方法不回滚事务
     *
     * 只在子方法上加注解不能回滚
     * @param userVO
     * @return
     */
    //@Transactional
    @Override
    public int saveUser4(UserVO userVO) {
        try {
            User user = new User();
            user.setName(userVO.getName());
            user.setAge(userVO.getAge());
            userService.insertWithTransactional(user);

            Address address = new Address();
            address.setUserId(user.getId());
            address.setAddr(userVO.getAddr());
            addressService.insertWithTransactional(address);
            Integer age = 100 / userVO.getAge();
            return 1;
        } catch (Exception e) {
            //关键点，出异常后回滚方法内的数据库操作
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("数据库操作异常", e);
        }
        return -1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveUser5(UserVO userVO) throws Exception {
        User user = new User();
        user.setName(userVO.getName());
        user.setAge(userVO.getAge());
        userService.insertWithoutTransactional(user);

        Address address = new Address();
        address.setUserId(user.getId());
        address.setAddr(userVO.getAddr());
        addressService.insertWithoutTransactional(address);
        Integer age = 100 / userVO.getAge();
        return 1;
    }
}
